/*
author:杨文超
email:yangwenchao@keynection.cn
*/
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include "esp_system.h"
#include "esp_log.h"
#include "geminai_log.h"
#include "esp_wifi.h"
#include "esp_netif.h"
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/lwip_napt.h"
#include "dhcpserver/dhcpserver.h"
#include "geminai_usbh_modem_wifi.h"
#include "geminai_usbh_modem_board.h"

static const char *TAG = "GEMINAI_4G_AP";
static int s_active_station_num = 0;
static esp_netif_t *s_wifi_netif[WIFI_MODE_MAX] = {NULL};

/* Event handler for catching system events */
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
    //if (event_base == IP_EVENT && event_id == IP_EVENT_AP_STAIPASSIGNED) {
    if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        //GEMINAI_LOGI(TAG, "Get IP addr");
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        GEMINAI_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
    } else if (event_base == WIFI_EVENT) {
        switch (event_id) {
        //case WIFI_EVENT_AP_START:
        //    ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        //    GEMINAI_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        //    break;
        case WIFI_EVENT_AP_STACONNECTED:
            if (s_active_station_num == 0) {
                modem_wifi_napt_enable(true);
            }
            if (++s_active_station_num > 0) {
                esp_event_post(MODEM_BOARD_EVENT, MODEM_EVENT_WIFI_STA_CONN, (void *)s_active_station_num, 0, 0);
            }
            break;
        case WIFI_EVENT_AP_STADISCONNECTED:
            if (--s_active_station_num == 0) {
                esp_event_post(MODEM_BOARD_EVENT, MODEM_EVENT_WIFI_STA_DISCONN, (void *)s_active_station_num, 0, 0);
                //TODO: esp-lwip NAPT now have a bug, disable then enable NAPT will cause random table index
                //modem_wifi_napt_enable(false);
            }
            break;
        default:
            break;
        }
    }
}

esp_netif_t *modem_wifi_init(wifi_mode_t mode)
{
    esp_netif_t *wifi_netif = NULL;

    if (mode & WIFI_MODE_STA) {
        wifi_netif = esp_netif_create_default_wifi_sta();
    }

    if (mode & WIFI_MODE_AP) {
        wifi_netif = esp_netif_create_default_wifi_ap();
    }

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    /* Register our event handler for Wi-Fi, IP and Provisioning related events */
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_wifi_set_mode(mode));
    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
    ESP_ERROR_CHECK(esp_wifi_start());
    GEMINAI_LOGI(TAG, "Wi-Fi %s started", mode == WIFI_MODE_STA ? "STA" : "AP");
    s_wifi_netif[mode] = wifi_netif;
    return wifi_netif;
}

uint32_t wifi_ap_get_local_ip(esp_netif_ip_info_t *ip_info)
{
    esp_netif_t *netif = s_wifi_netif[WIFI_MODE_AP];
    esp_netif_ip_info_t local_ip_info;
    esp_netif_get_ip_info(netif, &local_ip_info);
    if (ip_info != NULL) {
        *ip_info = local_ip_info;
    }

    return local_ip_info.ip.addr;
}

esp_netif_t *modem_wifi_ap_init(void)
{
    return modem_wifi_init(WIFI_MODE_AP);
}

esp_netif_t *modem_wifi_sta_init(void)
{
    return modem_wifi_init(WIFI_MODE_STA);
}

esp_err_t modem_wifi_set(modem_wifi_config_t *config)
{
    if (config == NULL || config->ssid[0] == 0 || config->password[0] == 0) {
        return ESP_ERR_INVALID_ARG;
    }

    wifi_config_t wifi_cfg = { 0 };

    if (config->mode & WIFI_MODE_STA) {
        strlcpy((char *)wifi_cfg.sta.ssid, config->ssid, sizeof(wifi_cfg.sta.ssid));
        strlcpy((char *)wifi_cfg.sta.password, config->password, sizeof(wifi_cfg.sta.password));
        ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_cfg));

        GEMINAI_LOGI(TAG, "sta ssid: %s password: %s", config->ssid, config->password);
    }

    if (config->mode & WIFI_MODE_AP) {
        wifi_cfg.ap.max_connection = config->max_connection;
        wifi_cfg.ap.authmode = config->authmode;
        wifi_cfg.ap.channel = config->channel;
        strlcpy((char *)wifi_cfg.ap.ssid, config->ssid, sizeof(wifi_cfg.ap.ssid));
        strlcpy((char *)wifi_cfg.ap.password, config->password, sizeof(wifi_cfg.ap.password));
        wifi_cfg.ap.ssid_hidden = config->ssid_hidden;
        ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_cfg));
        ESP_ERROR_CHECK(esp_wifi_set_bandwidth(ESP_IF_WIFI_AP, config->bandwidth));
        GEMINAI_LOGI(TAG, "softap ssid: %s password: %s", config->ssid, config->password);
        if (config->dns[0]) {
            uint32_t ap_dns_addr = inet_addr(config->dns);
            ESP_ERROR_CHECK(modem_wifi_set_dns(s_wifi_netif[WIFI_MODE_AP], ap_dns_addr));
            GEMINAI_LOGI(TAG, "ap dns addr(manual): %s", config->dns);
        } else {
            uint32_t ap_dns_addr = inet_addr(CONFIG_MODEM_WIFI_DEFAULT_DNS);
            ESP_ERROR_CHECK(modem_wifi_set_dns(s_wifi_netif[WIFI_MODE_AP], ap_dns_addr));
            GEMINAI_LOGI(TAG, "ap dns addr(default): %s", CONFIG_MODEM_WIFI_DEFAULT_DNS);
        }
    }
    return ESP_OK;
}

esp_err_t modem_wifi_napt_enable(bool enable)
{
    ip_napt_enable(_g_esp_netif_soft_ap_ip.ip.addr, enable);
    GEMINAI_LOGI(TAG, "NAT is %s", enable ? "enabled" : "disabled");
    return ESP_OK;
}

esp_err_t modem_wifi_set_dns(esp_netif_t *netif, uint32_t addr)
{
    esp_netif_dns_info_t dns;
    dns.ip.u_addr.ip4.addr = addr;
    dns.ip.type = IPADDR_TYPE_V4;
    dhcps_offer_t dhcps_dns_value = OFFER_DNS;
    esp_netif_dhcps_stop(netif);
    ESP_ERROR_CHECK(esp_netif_dhcps_option(netif, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dhcps_dns_value, sizeof(dhcps_dns_value)));
    ESP_ERROR_CHECK(esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns));
    esp_netif_dhcps_start(netif);
    return ESP_OK;
}


uint16_t channel_to_freq(uint8_t channel) ;

esp_err_t test_wifi_collect_para(scan_result_t* scan_result) 
{
    esp_err_t ret;

    // Wi-Fi 初始化配置
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ret = esp_wifi_init(&cfg);
    if (ret != ESP_OK) {
        return ret; // 返回错误
    }

    // 设置 Wi-Fi 模式为 STA
    ret = esp_wifi_set_mode(WIFI_MODE_STA);
    if (ret != ESP_OK) {
        return ret; // 返回错误
    }

    // 启动 Wi-Fi
    ret = esp_wifi_start();
    if (ret != ESP_OK) {
        return ret; // 返回错误
    }

    // 开始 Wi-Fi 扫描
    ret = esp_wifi_scan_start(NULL, true);
    if (ret != ESP_OK) {
        return ret; // 返回错误
    }

    // 等待扫描完成，可根据需要增加延迟
    vTaskDelay(2000 / portTICK_PERIOD_MS); // 等待 2 秒
    // 获取 AP 数量
    uint16_t ap_count;
    ret = esp_wifi_scan_get_ap_num(&ap_count);
    if (ret != ESP_OK) {
        return ret; // 返回错误
    }

    scan_result->number = ap_count;

    // 分配内存以存储 AP 记录
    scan_result->wifi_para = (wifi_param_t*)malloc(sizeof(wifi_param_t) * ap_count);
    if (scan_result->wifi_para == NULL) {
        return ESP_ERR_NO_MEM; // 内存分配失败
    }

    // 获取 AP 记录
    wifi_ap_record_t *ap_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * ap_count);
    if (ap_records == NULL) {
        free(scan_result->wifi_para); // 释放已分配的内存
        return ESP_ERR_NO_MEM; // 内存分配失败
    }

    ret = esp_wifi_scan_get_ap_records(&ap_count, ap_records);
    if (ret != ESP_OK) {
        free(ap_records); // 释放已分配的内存
        free(scan_result->wifi_para); // 释放已分配的内存
        scan_result->wifi_para = NULL; // 避免悬空指针
        return ret; // 返回错误
    }

    // 将获取到的 AP 记录拷贝到 scan_result 中
    for (uint16_t i = 0; i < ap_count; i++) {
        scan_result->wifi_para[i].freq = channel_to_freq(ap_records[i].primary); // 这里假设使用 primary 作为频率
        scan_result->wifi_para[i].signal = ap_records[i].rssi; // 假设使用 rssi 作为信号强度
        strncpy(scan_result->wifi_para[i].ssid, (char*)ap_records[i].ssid, sizeof(scan_result->wifi_para[i].ssid));
        strncpy(scan_result->wifi_para[i].mac, (char*)ap_records[i].bssid, sizeof(scan_result->wifi_para[i].mac));

        // 使用 ESP-IDF 的日志功能打印 SSID、MAC、主频道和信号强度
/*         GEMINAI_LOGI(TAG, "SSID: %s", scan_result->wifi_para[i].ssid);
        GEMINAI_LOGI(TAG, "MAC: %02X:%02X:%02X:%02X:%02X:%02X", 
                ap_records[i].bssid[0], ap_records[i].bssid[1], 
                ap_records[i].bssid[2], ap_records[i].bssid[3], 
                ap_records[i].bssid[4], ap_records[i].bssid[5]);
        GEMINAI_LOGI(TAG, "Primary Channel: %d", ap_records[i].primary);
        GEMINAI_LOGI(TAG, "RSSI: %d", ap_records[i].rssi);
        GEMINAI_LOGI(TAG,"--------------------------------------"); */
    }


    // 释放临时 AP 记录内存
    free(ap_records);

    ret = esp_wifi_set_mode(WIFI_MODE_AP);
    if (ret != ESP_OK) {
        return ret; // 返回错误
    }

    return ESP_OK; // 成功
}

uint16_t channel_to_freq(uint8_t channel) 
{
    if (channel >= 1 && channel <= 14) {
        return 2400 + (5 * channel); // 2.4GHz 频段
    } else if (channel >= 36 && channel <= 165) {
        return 5000 + (5 * (channel - 36)); // 5GHz 频段
    }
    return 0; // 不支持的信道
}

void test_wifi_collect()
{
    scan_result_t result;
    while (1)
    {
        test_wifi_collect_para(&result);
        // 遍历并打印每个 Wi-Fi 参数
        for (uint16_t i = 0; i < result.number; i++) {
            GEMINAI_LOGI(TAG, "SSID: %s", result.wifi_para[i].ssid);

            // 格式化并打印 MAC 地址
            char mac_str[18]; // MAC 地址字符串长度为 17 + 1 (结束符)
            snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X",
                     result.wifi_para[i].mac[0],
                     result.wifi_para[i].mac[1],
                     result.wifi_para[i].mac[2],
                     result.wifi_para[i].mac[3],
                     result.wifi_para[i].mac[4],
                     result.wifi_para[i].mac[5]);
            GEMINAI_LOGI(TAG, "MAC: %s", mac_str);
            
            GEMINAI_LOGI(TAG, "频率: %u MHz", result.wifi_para[i].freq);
            GEMINAI_LOGI(TAG, "信号强度: %d dBm", result.wifi_para[i].signal);
            GEMINAI_LOGI(TAG, "------------------------");
        }
        vTaskDelay(1500 / portTICK_PERIOD_MS);
    }
}
void task_test_wifi_collect()
{
    xTaskCreate(test_wifi_collect,"test_wifi_collect",4096,NULL,11,NULL);
}